home *** CD-ROM | disk | FTP | other *** search
/ The Complete Utilities To…ka 501 Killer Utilities! / 501 Killer Utilities! (Macworld July 1995).cdr / Programming / OutOfPhase1.1 Source / OutOfPhase Folder / ExecuteSynthesis.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-01-05  |  21.2 KB  |  578 lines  |  [TEXT/KAHL]

  1. /* ExecuteSynthesis.c */
  2. /*****************************************************************************/
  3. /*                                                                           */
  4. /*    Out Of Phase:  Digital Music Synthesis on General Purpose Computers    */
  5. /*    Copyright (C) 1994  Thomas R. Lawrence                                 */
  6. /*                                                                           */
  7. /*    This program is free software; you can redistribute it and/or modify   */
  8. /*    it under the terms of the GNU General Public License as published by   */
  9. /*    the Free Software Foundation; either version 2 of the License, or      */
  10. /*    (at your option) any later version.                                    */
  11. /*                                                                           */
  12. /*    This program is distributed in the hope that it will be useful,        */
  13. /*    but WITHOUT ANY WARRANTY; without even the implied warranty of         */
  14. /*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          */
  15. /*    GNU General Public License for more details.                           */
  16. /*                                                                           */
  17. /*    You should have received a copy of the GNU General Public License      */
  18. /*    along with this program; if not, write to the Free Software            */
  19. /*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.              */
  20. /*                                                                           */
  21. /*    Thomas R. Lawrence can be reached at tomlaw@world.std.com.             */
  22. /*                                                                           */
  23. /*****************************************************************************/
  24.  
  25. #include "MiscInfo.h"
  26. #include "Audit.h"
  27. #include "Debug.h"
  28. #include "Definitions.h"
  29.  
  30. #include "ExecuteSynthesis.h"
  31. #include "Memory.h"
  32. #include "MainWindowStuff.h"
  33. #include "LinearTransition.h"
  34. #include "PlayTrackInfoThang.h"
  35. #include "Array.h"
  36. #include "WaveTableOscControl.h"
  37. #include "EnvelopeState.h"
  38. #include "LFOGenerator.h"
  39. #include "InstrList.h"
  40. #include "InstrObject.h"
  41. #include "TrackObject.h"
  42. #include "SampleOscControl.h"
  43. #include "Fractions.h"
  44. #include "FrameObject.h"
  45. #include "DeterminedNoteStructure.h"
  46. #include "TempoController.h"
  47. #include "OscBankPlayer.h"
  48. #include "DataMunging.h"
  49. #include "Alert.h"
  50. #include "CheckNameUniqueness.h"
  51. #include "ErrorDaemon.h"
  52. #include "TrackEffectGenerator.h"
  53. #include "DelayLine.h"
  54. #include "NLProc.h"
  55. #include "FilterFirstOrderLowpass.h"
  56. #include "FilterFirstOrderHighpass.h"
  57. #include "FilterSecondOrderReson.h"
  58. #include "FilterSecondOrderZero.h"
  59. #include "FilterButterworthLowpass.h"
  60. #include "FilterButterworthHighpass.h"
  61. #include "FilterButterworthBandpass.h"
  62. #include "FilterButterworthBandreject.h"
  63. #include "FilterNull.h"
  64. #include "FilterArray.h"
  65. #include "Analyzer.h"
  66. #include "EffectSpecList.h"
  67.  
  68.  
  69. typedef struct PlayListNodeRec
  70.     {
  71.         struct PlayListNodeRec*    Next;
  72.         PlayTrackInfoRec*                ThisTrack;
  73.     } PlayListNodeRec;
  74.  
  75.  
  76. /* build the list of objects involved in playing. */
  77. static SynthErrorCodes    BuildPlayList(PlayListNodeRec** ListOut,
  78.                                                 ArrayRec* TrackObjectList, MyBoolean InStereoFlag,
  79.                                                 MainWindowRec* MainWindow,
  80.                                                 LargeBCDType OverallVolumeScalingReciprocal,
  81.                                                 long SamplingRate, long EnvelopeRate, MyBoolean TimeInterp,
  82.                                                 MyBoolean WaveInterp, TempoControlRec* TempoControl,
  83.                                                 long ScanningGapWidthInEnvelopeTicks,
  84.                                                 ErrorDaemonRec* ErrorDaemon, TrackEffectGenRec* ScoreEffectProcessor)
  85.     {
  86.         PlayListNodeRec*        TrackPlayList;
  87.         long                                Scan;
  88.         long                                Limit;
  89.         InstrListRec*                InstrList;
  90.         SynthErrorCodes            Error;
  91.  
  92.         /* build list of tracks */
  93.         CheckPtrExistence(MainWindow);
  94.         CheckPtrExistence(TrackObjectList);
  95.         InstrList = MainWindowGetInstrList(MainWindow);
  96.         TrackPlayList = NIL;
  97.         Limit = ArrayGetLength(TrackObjectList);
  98.         for (Scan = 0; Scan < Limit; Scan += 1)
  99.             {
  100.                 TrackObjectRec*            PossibleTrack;
  101.                 PlayListNodeRec*        NewListNode;
  102.                 PlayTrackInfoRec*        TrackPlayObject;
  103.                 InstrObjectRec*            BaseInstrument;
  104.                 char*                                InstrumentNameCopy;
  105.  
  106.                 /* get the track */
  107.                 PossibleTrack = (TrackObjectRec*)ArrayGetElement(TrackObjectList,Scan);
  108.                 CheckPtrExistence(PossibleTrack);
  109.                 /* get the instrument to be used */
  110.                 InstrumentNameCopy = TrackObjectGetInstrName(PossibleTrack);
  111.                 if (InstrumentNameCopy == NIL)
  112.                     {
  113.                         Error = eSynthNoMemory;
  114.                         goto TrackListBuildFailure1;
  115.                     }
  116.                 BaseInstrument = InstrListLookupNamedInstr(InstrList,InstrumentNameCopy);
  117.                 ReleasePtr(InstrumentNameCopy);
  118.                 if (BaseInstrument == NIL)
  119.                     {
  120.                         char*                                TrackName;
  121.                         MyBoolean                        MessageSuccess = False;
  122.  
  123.                         TrackName = TrackObjectGetNameCopy(PossibleTrack);
  124.                         if (TrackName != NIL)
  125.                             {
  126.                                 char*                                NullTerminated;
  127.  
  128.                                 NullTerminated = BlockToStringCopy(TrackName);
  129.                                 if (NullTerminated != NIL)
  130.                                     {
  131.                                         AlertHalt("The track '_' uses a nonexistent instrument.",
  132.                                             NullTerminated);
  133.                                         MessageSuccess = True;
  134.                                         ReleasePtr(NullTerminated);
  135.                                     }
  136.                                 ReleasePtr(TrackName);
  137.                             }
  138.                         if (!MessageSuccess)
  139.                             {
  140.                                 AlertHalt("A track uses a nonexistent instrument.",NIL);
  141.                             }
  142.                         Error = eSynthUndefinedInstrumentError;
  143.                         goto TrackListBuildFailure1;
  144.                     }
  145.                 /* build the track */
  146.                 TrackPlayObject = NewPlayTrackInfo(PossibleTrack,
  147.                     GetInstrObjectRawData(BaseInstrument),InStereoFlag,
  148.                     OverallVolumeScalingReciprocal,SamplingRate,EnvelopeRate,TimeInterp,
  149.                     WaveInterp,TempoControl,ScanningGapWidthInEnvelopeTicks,ErrorDaemon,
  150.                     MainWindow,ScoreEffectProcessor);
  151.                 if (TrackPlayObject == NIL)
  152.                     {
  153.                         Error = eSynthNoMemory;
  154.                      TrackListBuildFailure1:
  155.                         while (TrackPlayList != NIL)
  156.                             {
  157.                                 PlayListNodeRec*        Temp;
  158.  
  159.                                 DisposePlayTrackInfo(TrackPlayList->ThisTrack);
  160.                                 Temp = TrackPlayList;
  161.                                 TrackPlayList = TrackPlayList->Next;
  162.                                 ReleasePtr((char*)Temp);
  163.                             }
  164.                         return Error;
  165.                     }
  166.                 /* add this one to the list */
  167.                 NewListNode = (PlayListNodeRec*)AllocPtrCanFail(sizeof(PlayListNodeRec),
  168.                     "PlayListNodeRec");
  169.                 if (NewListNode == NIL)
  170.                     {
  171.                         Error = eSynthNoMemory;
  172.                      TrackListBuildFailure2:
  173.                         DisposePlayTrackInfo(TrackPlayObject);
  174.                         goto TrackListBuildFailure1;
  175.                     }
  176.                 NewListNode->ThisTrack = TrackPlayObject;
  177.                 NewListNode->Next = TrackPlayList;
  178.                 TrackPlayList = NewListNode;
  179.             }
  180.         *ListOut = TrackPlayList;
  181.         return eSynthDone;
  182.     }
  183.  
  184.  
  185. /* this routine scans through the key playlist and determines the exact point */
  186. /* at which playback should begin. */
  187. static void                        FindStartPoint(TrackObjectRec* KeyTrack, long FrameToStartAt,
  188.                                                 FractionRec* StartTimeOut)
  189.     {
  190.         long                                Scan;
  191.         FractionRec                    Counter;
  192.  
  193.         CheckPtrExistence(KeyTrack);
  194.         Counter.Integer = 0;
  195.         Counter.Fraction = 0;
  196.         Counter.Denominator = (64*3*5*7*2);
  197.         ERROR(FrameToStartAt > TrackObjectGetNumFrames(KeyTrack),PRERR(ForceAbort,
  198.             "FindStartPoint:  start frame is beyond end of track"));
  199.         for (Scan = 0; Scan < FrameToStartAt; Scan += 1)
  200.             {
  201.                 FrameObjectRec*            Frame;
  202.                 FractionRec                    TempDuration;
  203.  
  204.                 Frame = TrackObjectGetFrame(KeyTrack,Scan);
  205.                 CheckPtrExistence(Frame);
  206.                 DurationOfFrame(Frame,&TempDuration);
  207.                 AddFractions(&TempDuration,&Counter,&Counter);
  208.             }
  209.         *StartTimeOut = Counter;
  210.     }
  211.  
  212.  
  213. /* This routine does all of the work. */
  214. /* The DataOutCallback is called every time a block of data is */
  215. /* ready to be sent to the target device; this is provided so that data can be */
  216. /* redirected to a file or postprocessed in some way before playback. */
  217. /* the KeyTrack and FrameToStartAt provide a reference point indicating where */
  218. /* playback should occur.  if KeyTrack is NIL, then playback begins at the beginning. */
  219. /* the rate parameters are in operations per second. */
  220. SynthErrorCodes                Synthesizer(struct MainWindowRec* MainWindow,
  221.                                                 MyBoolean (*DataOutCallback)(void* Refcon,
  222.                                                     largefixedsigned* DataBlock, long NumFrames,
  223.                                                     MyBoolean* AbortPlaybackFlagOut),
  224.                                                 void* DataOutRefcon, struct ArrayRec* ListOfTracks,
  225.                                                 struct TrackObjectRec* KeyTrack, long FrameToStartAt,
  226.                                                 long SamplingRate, long EnvelopeRate, MyBoolean UseStereo,
  227.                                                 LargeBCDType DefaultBeatsPerMinute,
  228.                                                 LargeBCDType OverallVolumeScalingReciprocal,
  229.                                                 MyBoolean InterpOverTime, MyBoolean InterpAcrossWaves,
  230.                                                 LargeBCDType ScanningGap, ErrorDaemonRec* ErrorDaemon)
  231.     {
  232.         SynthErrorCodes            Error;
  233.  
  234.  
  235.         /* error checking */
  236.         CheckPtrExistence(MainWindow);
  237.         CheckPtrExistence(ListOfTracks);
  238.         CheckPtrExistence(ErrorDaemon);
  239.         ERROR(DataOutCallback == NIL,PRERR(ForceAbort,"Synthesizer: bad DataOutCallback"));
  240.         if (ScanningGap < 0)
  241.             {
  242.                 ScanningGap = 0;
  243.             }
  244.  
  245.         /* check to see that there aren't any naming ambiguities */
  246.         if (!CheckNameUniqueness(MainWindow))
  247.             {
  248.                 return eSynthDuplicateNames;
  249.             }
  250.  
  251.         /* make sure all objects are up to date */
  252.         if (MainWindowMakeEverythingUpToDate(MainWindow))
  253.             {
  254.                 largefixedsigned*        SampleArray;
  255.                 long                                SampleArrayLength;
  256.                 EffectSpecListRec*    ScoreEffectSpec;
  257.                 TrackEffectGenRec*    ScoreEffectProcessor;
  258.  
  259.                 ScoreEffectSpec = MainWindowGetScoreEffectsSpec(MainWindow);
  260.                 if (ScoreEffectSpec != NIL)
  261.                     {
  262.                         long                                ScanningGapWidthInEnvelopeTicks;
  263.  
  264.                         /* figure out how large the scanning gap is */
  265.                         ScanningGapWidthInEnvelopeTicks = LargeBCD2Double(ScanningGap) * EnvelopeRate;
  266.  
  267.                         ScoreEffectProcessor = NewTrackEffectGenerator(ScoreEffectSpec,SamplingRate,
  268.                             UseStereo,LargeBCD2Single(OverallVolumeScalingReciprocal),MainWindow,
  269.                             ScanningGapWidthInEnvelopeTicks);
  270.                         if (ScoreEffectProcessor != NIL)
  271.                             {
  272.                                 SampleArrayLength = 1000;
  273.                                 SampleArray = (largefixedsigned*)AllocPtrCanFail(SampleArrayLength
  274.                                     * sizeof(largefixedsigned),"SampleArray");
  275.                                 if (SampleArray != NIL)
  276.                                     {
  277.                                         TempoControlRec*        TempoControl;
  278.  
  279.                                         TempoControl = NewTempoControl(DefaultBeatsPerMinute);
  280.                                         if (TempoControl != NIL)
  281.                                             {
  282.                                                 PlayListNodeRec*        PlayTrackList;
  283.  
  284.                                                 Error = BuildPlayList(&PlayTrackList,ListOfTracks,UseStereo,
  285.                                                     MainWindow,OverallVolumeScalingReciprocal,SamplingRate,
  286.                                                     EnvelopeRate,InterpOverTime,InterpAcrossWaves,TempoControl,
  287.                                                     ScanningGapWidthInEnvelopeTicks,ErrorDaemon,ScoreEffectProcessor);
  288.                                                 if (Error == eSynthDone)
  289.                                                     {
  290.                                                         PlayListNodeRec*        Scan;
  291.                                                         PlayListNodeRec*        Lag;
  292.                                                         MyBoolean                        AbortPlaybackFlag;
  293.                                                         FractionRec                    MomentOfStarting;
  294.                                                         LargeBCDType                CurrentBeatsPerMinute;
  295.                                                         long                                ScanningGapFrontInEnvelopeTicks;
  296.                                                         double                            EnvelopeClockAccumulatorFraction;
  297.                                                         double                            NoteDurationClockAccumulatorFraction;
  298.                                                         double                            SamplesPerEnvelopeClock;
  299.                                                         double                            DurationTicksPerEnvelopeClock;
  300.  
  301.                                                         /* calculate the moment of starting for tracks */
  302.                                                         FindStartPoint(KeyTrack,FrameToStartAt,&MomentOfStarting);
  303.                                                         /* cue all tracks up to this point */
  304.                                                         Scan = PlayTrackList;
  305.                                                         while (Scan != NIL)
  306.                                                             {
  307.                                                                 if (!CuePlayTrackInfoToPoint(Scan->ThisTrack,&MomentOfStarting))
  308.                                                                     {
  309.                                                                         Error = eSynthNoMemory;
  310.                                                                         goto PlaybackFailurePoint;
  311.                                                                     }
  312.                                                                 Scan = Scan->Next;
  313.                                                             }
  314.  
  315.                                                         /* this value is for determining when in REAL time (not score time) */
  316.                                                         /* each note begins */
  317.                                                         ScanningGapFrontInEnvelopeTicks = 0;
  318.  
  319.                                                         /* initialize tempo thing */
  320.                                                         CurrentBeatsPerMinute = DefaultBeatsPerMinute;
  321.  
  322.                                                         /* initialize accumulators */
  323.                                                         EnvelopeClockAccumulatorFraction = 0;
  324.                                                         NoteDurationClockAccumulatorFraction = 0;
  325.                                                         /* calculate increment factors */
  326.                                                         SamplesPerEnvelopeClock = (double)SamplingRate / EnvelopeRate;
  327.                                                         DurationTicksPerEnvelopeClock = ((LargeBCD2Double(DefaultBeatsPerMinute)
  328.                                                             / (4/*beats per whole note*/ * 60/*seconds per minute*/))
  329.                                                             / EnvelopeRate) * DURATIONUPDATECLOCKRESOLUTION;
  330.  
  331.                                                         /* play */
  332.                                                         AbortPlaybackFlag = False;
  333.                                                         while ((PlayTrackList != NIL) && !AbortPlaybackFlag)
  334.                                                             {
  335.                                                                 long                                NumSampleFrames;
  336.                                                                 long                                NumNoteDurationTicks;
  337.                                                                 LargeBCDType                OldBeatsPerMinute;
  338.                                                                 MyBoolean                        UpdateEnvelopes;
  339.  
  340.                                                                 /* figure out how many note duration ticks to generate */
  341.                                                                 /* increment counter */
  342.                                                                 NoteDurationClockAccumulatorFraction += DurationTicksPerEnvelopeClock;
  343.                                                                 /* round down */
  344.                                                                 NumNoteDurationTicks = (long)NoteDurationClockAccumulatorFraction;
  345.                                                                 /* subtract off what we're taking out this time around, */
  346.                                                                 /* leaving the extra little bit in there */
  347.                                                                 NoteDurationClockAccumulatorFraction -= NumNoteDurationTicks;
  348.  
  349.                                                                 /* figure out how many samples to do before the next envelope */
  350.                                                                 if (ScanningGapFrontInEnvelopeTicks >= ScanningGapWidthInEnvelopeTicks)
  351.                                                                     {
  352.                                                                         /* we're really sampling stuff */
  353.                                                                         EnvelopeClockAccumulatorFraction += SamplesPerEnvelopeClock;
  354.                                                                         NumSampleFrames = (long)EnvelopeClockAccumulatorFraction;
  355.                                                                         EnvelopeClockAccumulatorFraction -= NumSampleFrames;
  356.                                                                     }
  357.                                                                  else
  358.                                                                     {
  359.                                                                         /* scanning gap is still opening, so we're not sampling */
  360.                                                                         NumSampleFrames = 0;
  361.                                                                     }
  362.  
  363.                                                                 /* see if we need to resize the output workspace array */
  364.                                                                 if (UseStereo)
  365.                                                                     {
  366.                                                                         long                                Scan;
  367.  
  368.                                                                         /* stereo array sizing */
  369.                                                                         if (NumSampleFrames * 2 > SampleArrayLength)
  370.                                                                             {
  371.                                                                                 largefixedsigned*        TempArray;
  372.  
  373.                                                                                 TempArray = (largefixedsigned*)ResizePtr(
  374.                                                                                     (char*)SampleArray,NumSampleFrames * 2
  375.                                                                                     * sizeof(largefixedsigned));
  376.                                                                                 if (TempArray == NIL)
  377.                                                                                     {
  378.                                                                                         Error = eSynthNoMemory;
  379.                                                                                         goto PlaybackFailurePoint;
  380.                                                                                     }
  381.                                                                                 SampleArray = TempArray;
  382.                                                                                 SampleArrayLength = NumSampleFrames * 2;
  383.                                                                             }
  384.                                                                         /* initialize the array */
  385.                                                                         for (Scan = 0; Scan < NumSampleFrames * 2; Scan += 1)
  386.                                                                             {
  387.                                                                                 PRNGCHK(SampleArray,&(SampleArray[Scan]),
  388.                                                                                     sizeof(SampleArray[Scan]));
  389.                                                                                 SampleArray[Scan] = 0;
  390.                                                                             }
  391.                                                                     }
  392.                                                                  else
  393.                                                                     {
  394.                                                                         long                                Scan;
  395.  
  396.                                                                         /* mono array sizing */
  397.                                                                         if (NumSampleFrames > SampleArrayLength)
  398.                                                                             {
  399.                                                                                 largefixedsigned*        TempArray;
  400.  
  401.                                                                                 TempArray = (largefixedsigned*)ResizePtr(
  402.                                                                                     (char*)SampleArray,NumSampleFrames
  403.                                                                                     * sizeof(largefixedsigned));
  404.                                                                                 if (TempArray == NIL)
  405.                                                                                     {
  406.                                                                                         Error = eSynthNoMemory;
  407.                                                                                         goto PlaybackFailurePoint;
  408.                                                                                     }
  409.                                                                                 SampleArray = TempArray;
  410.                                                                                 SampleArrayLength = NumSampleFrames;
  411.                                                                             }
  412.                                                                         /* initialize the array */
  413.                                                                         for (Scan = 0; Scan < NumSampleFrames; Scan += 1)
  414.                                                                             {
  415.                                                                                 PRNGCHK(SampleArray,&(SampleArray[Scan]),
  416.                                                                                     sizeof(SampleArray[Scan]));
  417.                                                                                 SampleArray[Scan] = 0;
  418.                                                                             }
  419.                                                                     }
  420.  
  421.                                                                 /* perform execution cyle */
  422.                                                                 Scan = PlayTrackList;
  423.                                                                 Lag = NIL;
  424.                                                                 /* this condition is responsible for opening the scanning gap */
  425.                                                                 UpdateEnvelopes = (ScanningGapFrontInEnvelopeTicks
  426.                                                                     >= ScanningGapWidthInEnvelopeTicks);
  427.                                                                 while (Scan != NIL)
  428.                                                                     {
  429.                                                                         if (!PlayTrackUpdate(Scan->ThisTrack,
  430.                                                                             UpdateEnvelopes/*scanning gap control*/,
  431.                                                                             NumNoteDurationTicks,NumSampleFrames,SampleArray,
  432.                                                                             /* envelope ticks per duration tick */
  433.                                                                             (float)(1 / DurationTicksPerEnvelopeClock),
  434.                                                                             ScanningGapFrontInEnvelopeTicks))
  435.                                                                             {
  436.                                                                                 Error = eSynthNoMemory;
  437.                                                                                 goto PlaybackFailurePoint;
  438.                                                                             }
  439.                                                                         if (PlayTrackIsItStillActive(Scan->ThisTrack))
  440.                                                                             {
  441.                                                                                 Lag = Scan;
  442.                                                                                 Scan = Scan->Next;
  443.                                                                             }
  444.                                                                          else
  445.                                                                             {
  446.                                                                                 PlayListNodeRec*        Temp;
  447.  
  448.                                                                                 if (Lag == NIL)
  449.                                                                                     {
  450.                                                                                         PlayTrackList = Scan->Next;
  451.                                                                                     }
  452.                                                                                  else
  453.                                                                                     {
  454.                                                                                         Lag->Next = Scan->Next;
  455.                                                                                     }
  456.                                                                                 Temp = Scan;
  457.                                                                                 Scan = Scan->Next;
  458.                                                                                 DisposePlayTrackInfo(Temp->ThisTrack);
  459.                                                                                 ReleasePtr((char*)Temp);
  460.                                                                             }
  461.                                                                     }
  462.                                                                 if (UpdateEnvelopes)
  463.                                                                     {
  464.                                                                         /* if we are generating samples, then we should */
  465.                                                                         /* apply the score effects processor */
  466.                                                                         TrackEffectProcessQueuedCommands(ScoreEffectProcessor);
  467.                                                                         ApplyTrackEffectGenerator(ScoreEffectProcessor,
  468.                                                                             SampleArray,NumSampleFrames);
  469.                                                                     }
  470.                                                                 /* update effects, but only AFTER they have been applied, */
  471.                                                                 /* so that parameters come from the leading edge of an */
  472.                                                                 /* envelope period, rather than the trailing edge. */
  473.                                                                 TrackEffectIncrementDurationTimer(ScoreEffectProcessor,
  474.                                                                     NumNoteDurationTicks);
  475.  
  476.                                                                 /* keep track of what time it is */
  477.                                                                 ScanningGapFrontInEnvelopeTicks += 1;
  478.  
  479.                                                                 /* submit the data */
  480.                                                                 AbortPlaybackFlag = False;
  481.                                                                 if (!(*DataOutCallback)(DataOutRefcon,SampleArray,NumSampleFrames,
  482.                                                                     &AbortPlaybackFlag)) /* DataOutRefcon knows about stereo status */
  483.                                                                     {
  484.                                                                         Error = eSynthDataSubmitError;
  485.                                                                         goto PlaybackFailurePoint;
  486.                                                                     }
  487.  
  488.                                                                 /* and also do the tempo generator */
  489.                                                                 OldBeatsPerMinute = CurrentBeatsPerMinute;
  490.                                                                 CurrentBeatsPerMinute = TempoControlUpdate(TempoControl,
  491.                                                                     NumNoteDurationTicks);
  492.                                                                 if (OldBeatsPerMinute != CurrentBeatsPerMinute)
  493.                                                                     {
  494.                                                                         /* tempo changed, so we have to adjust the clock */
  495.                                                                         DurationTicksPerEnvelopeClock = ((LargeBCD2Double(CurrentBeatsPerMinute)
  496.                                                                             / (4/*beats per whole note*/ * 60/*seconds per minute*/))
  497.                                                                             / EnvelopeRate) * DURATIONUPDATECLOCKRESOLUTION;
  498.                                                                     }
  499.                                                             }
  500.                                                         if (AbortPlaybackFlag)
  501.                                                             {
  502.                                                                 Error = eSynthUserCancelled;
  503.                                                             }
  504.  
  505.                                                      PlaybackFailurePoint:
  506.                                                         ;
  507.  
  508.                                                         /* clean up */
  509.                                                         while (PlayTrackList != NIL)
  510.                                                             {
  511.                                                                 PlayListNodeRec*        Temp;
  512.  
  513.                                                                 DisposePlayTrackInfo(PlayTrackList->ThisTrack);
  514.                                                                 Temp = PlayTrackList;
  515.                                                                 PlayTrackList = PlayTrackList->Next;
  516.                                                                 ReleasePtr((char*)Temp);
  517.                                                             }
  518.                                                     }
  519.  
  520.                                                 DisposeTempoControl(TempoControl);
  521.                                             }
  522.  
  523.                                         /* clean up */
  524.                                         ReleasePtr((char*)SampleArray);
  525.                                     }
  526.                                  else
  527.                                     {
  528.                                         Error = eSynthNoMemory; /* no memory for sample array */
  529.                                     }
  530.  
  531.                                 /* clean up */
  532.                                 DisposeTrackEffectGenerator(ScoreEffectProcessor);
  533.                             }
  534.                          else
  535.                             {
  536.                                 Error = eSynthNoMemory; /* no memory for score effect processor */
  537.                             }
  538.  
  539.                         /* clean up */
  540.                         DisposeEffectSpecList(ScoreEffectSpec);
  541.                     }
  542.                  else
  543.                     {
  544.                         Error = eSynthPrereqError; /* couldn't compile score effect thing */
  545.                     }
  546.             }
  547.          else
  548.             {
  549.                 Error = eSynthPrereqError; /* couldn't compile score elements */
  550.             }
  551.  
  552.         /* clean up */
  553.         FlushLinearTransitionRecords();
  554.         FlushWaveTableOscControl();
  555.         FlushSampleOscControl();
  556.         FlushEvalEnvelopeStateRecords();
  557.         FlushLFOGeneratorRecords();
  558.         FlushPlayTrackInfo();
  559.         FlushFrozenNoteStructures();
  560.         FlushCachedOscStateBankRecords();
  561.         FlushTrackEffectGeneratorInfo();
  562.         FlushCachedDelayLineStuff();
  563.         FlushCachedNLProcStuff();
  564.         FlushCachedFirstOrderLowpassStuff();
  565.         FlushCachedFirstOrderHighpassStuff();
  566.         FlushCachedSecondOrderResonStuff();
  567.         FlushCachedSecondOrderZeroStuff();
  568.         FlushCachedButterworthLowpassStuff();
  569.         FlushCachedButterworthHighpassStuff();
  570.         FlushCachedButterworthBandpassStuff();
  571.         FlushCachedButterworthBandrejectStuff();
  572.         FlushCachedFilterNullStuff();
  573.         FlushCachedFilterArrayStuff();
  574.         FlushCachedAnalyzerStuff();
  575.  
  576.         return Error;
  577.     }
  578.